<template>
	<div class="components-edit-shape" @click="handleTopWrapperClick" @mousedown="handleMouseDownOnElement" :class="{active: active, locked: locked}">
		<div class="edit-shape-point" v-for="item in (active ? pointList : [])" :key="item" @mousedown="handleMouseDownOnPoint(item)" :style="getPointStyle(item)"></div>
		<slot></slot>
	</div>
</template>
 
<script>
	import runAnimations from '@/utils/run-animate'
	export default {
		name: 'ResizeWidget',
		props: {
			active: {
				type: Boolean,
				default: false
			},
			defaultStyle: {
				require: true,
				type: Object
			},
			locked: {
				type: Boolean,
				default: false
			},
			wrapId: {
				type: String,
				default: ''
			},
			scale: {
				type: Number,
				default: 1
			},
			uuid: String
		},
		data() {
			return {
				// l = left, t = top, r = right, b = bottom
				pointList: ['lt', 'rt', 'lb', 'rb', 'l', 'r', 't', 'b'],
				// 上下左右 对应的 东南西北
				directionKey: {
					t: 'n',
					b: 's',
					l: 'w',
					r: 'e'
				}
			}
		},
		mounted() {
			this.animatePlaying = false
			this.$EventBus.$on('RUN_ANIMATIONS', (uuid, animations) => {
				if(uuid !== this.uuid) {
					return
				}
				// 正在执行的动画不允许插入新动画
				if(this.animatePlaying) return
				// let cssText = this.$el.style.cssText
				this.animatePlaying = true
				let cssText = this.$el.style.cssText
				runAnimations(this.$el, animations, true, () => {
					this.$el.style.cssText = cssText
					this.animatePlaying = false
				})
			})
		},
		methods: {
			/**
			 * 获取point计算后样式
			 * @param point
			 * @returns {{}}
			 */
			getPointStyle(point) {
				const pos = this.defaultStyle || {}
				const height = pos.height || 0
				const width = pos.width || 0
				let hasT = /t/.test(point)
				let hasB = /b/.test(point)
				let hasL = /l/.test(point)
				let hasR = /r/.test(point)
				let newLeft = 0
				let newTop = 0
				if(point.length === 2) {
					newLeft = hasL ? 0 : width
					newTop = hasT ? 0 : height
				} else {
					// !#zh 上下点，宽度固定在中间
					if(hasT || hasB) {
						newLeft = width / 2
						newTop = hasT ? 0 : height
					}
					// !#zh 左右点，高度固定在中间
					if(hasL || hasR) {
						newLeft = hasL ? 0 : width
						newTop = height / 2
					}
				}
				const style = {
					marginLeft: hasL || hasR ? '-5px' : 0,
					marginTop: hasT || hasB ? '-5px' : 0,
					left: `${newLeft}px`,
					top: `${newTop}px`,
					cursor: point
						.split('')
						.reverse()
						.map((m) => this.directionKey[m])
						.join('') + '-resize'
				}
				
				return style
			},
			/**
			 * 点击事件，点击后设置当前元素为选中元素
			 */
			handleTopWrapperClick(e) {
				e.stopPropagation()
				e.preventDefault()
			},
			/**
			 * 鼠标选中元素拖拽事件
			 * @param e
			 */
			handleMouseDownOnElement(e) { 
				// 抛出事件让父组件设置当前元素选中状态
				this.$emit('on-element-click')
				if(this.locked) {
					return false
				}
				if(e.which === 3) {
					return false
				}
				// !#zh 移动的时候，不需要向后代元素传递事件，只需要单纯的移动就OK
				e.stopPropagation()
				e.preventDefault && e.preventDefault()

				const oDrag = e.currentTarget
				let width = oDrag.offsetWidth;
				let height = oDrag.offsetHeight;

				const pos = { ...this.defaultStyle
				}
				let startY = e.clientY / this.scale
				let startX = e.clientX / this.scale
				let startTop = pos.top
				let startLeft = pos.left
				let firstTime = ''
				let lastTime = ''
				firstTime = new Date().getTime()
				// 容器
				const container = this.findPosition();
				const containerLeft = container[0];
				const containerTop = container[1];
				const containerWidth = container[4];
				const containerHeight = container[5];
				//开始 X 坐标。
				let cX = 0;
				//开始 Y 坐标。
				let cY = 0;
				//结束 X 坐标。
				let maxX = cX + containerWidth - width;
				//结束 Y 坐标。
				var maxY = cY + containerHeight - height;

				let move = (moveEvent) => {
					moveEvent = moveEvent || window.event || arguments.callee.caller.arguments[0];
					// !#zh 移动的时候，不需要向后代元素传递事件，只需要单纯的移动就OK
					moveEvent.stopPropagation()
					moveEvent.preventDefault && moveEvent.preventDefault()

					let currX = moveEvent.clientX / this.scale
					let currY = moveEvent.clientY / this.scale
					let mLeft = currX - startX + startLeft
					let mTop = currY - startY + startTop
					if(mLeft < cX) {
						mLeft = cX
					}
					if(mTop < cY) {
						mTop = cY
					}
					if(mLeft > maxX) {
						mLeft = maxX
					}
					if(mTop > maxY) {
						mTop = maxY
					}
					pos.top = mTop
					pos.left = mLeft
					oDrag.style.top = `${pos.top}px`
					oDrag.style.left = `${pos.left}px`
				}
				let up = () => {
					this.$emit('on-resize', pos)
					document.onmousemove = function() {}
					document.onmouseup = function() {}
				}
				document.onmousemove = move
				document.onmouseup = up
				return true
			},
			/**
			 * 鼠标点击可以的按钮resize事件
			 * @param point
			 * @param downEvent
			 */
			handleMouseDownOnPoint(point) {  
				if(this.locked) {
					return false
				}
				let downEvent = event
				// 抛出事件让父组件设置当前元素选中状态
				this.$emit('on-element-click')
				downEvent.stopPropagation()
				downEvent && downEvent.preventDefault() // Let's stop this event.
				const pos = { ...this.defaultStyle
				}
				let height = pos.height
				let width = pos.width
				let top = pos.top
				let left = pos.left
				let startX = downEvent.clientX / this.scale
				let startY = downEvent.clientY / this.scale

				// 边界容器
				const container = this.findPosition();
				const containerLeft = container[0];
				const containerTop = container[1];
				const containerWidth = container[4];
				const containerHeight = container[5];
				//开始 X 坐标。
				let cX = 0;
				//开始 Y 坐标。
				let cY = 0;
				//结束 X 坐标。
				let maxX = cX + containerWidth - width;
				//结束 Y 坐标。
				let maxY = cY + containerHeight - height;

				let move = (moveEvent) => {
					let currX = moveEvent.clientX / this.scale
					let currY = moveEvent.clientY / this.scale
					let disY = currY - startY
					let disX = currX - startX
					let hasT = /t/.test(point)
					let hasB = /b/.test(point)
					let hasL = /l/.test(point)
					let hasR = /r/.test(point)
					// 获取新位置
					let newLeft = +left + (hasL ? disX : 0)
					let newTop = +top + (hasT ? disY : 0)
					let newWidth, newHeight
					if(newLeft >= 0) {
						newWidth = +width + (hasL ? -disX : hasR ? disX : 0)
					} else {
						newWidth = width + left;
					}
					if(newTop >= 0) {
						newHeight = +height + (hasT ? -disY : hasB ? disY : 0)
					} else {
						newHeight = height + top;
					}
					if((hasL) && newWidth <= 50) {
						newWidth = 50;
						newLeft = left + (width - newWidth);
					}
					if(point === 'lt') {
						if(newWidth <= 50) {
							newWidth = 50;
							newLeft = left + (width - newWidth);
						}
						if(newHeight <= 50) {
							newHeight = 50;
							newTop = top + (height - newHeight);
						}
					}
					if(point === 'rt') {
						if(newWidth <= 50) {
							newWidth = 50;
							newLeft = left;
						}
						if(newHeight <= 50) {
							newHeight = 50;
							newTop = top + (height - newHeight);
						}
					}

					if(point === 't') {
						if(newHeight <= 50) {
							newHeight = 50;
							newTop = top + (height - newHeight);
						}
					}
					if(newLeft + newWidth > containerWidth) {
						newWidth = containerWidth - newLeft;
					}
					if(newTop + newHeight > containerHeight) {
						newHeight = containerHeight - newTop;
					}
					pos.height = newHeight > 50 ? newHeight : 50
					pos.width = newWidth > 50 ? newWidth : 50
					pos.left = newLeft > 0 ? newLeft : 0
					pos.top = newTop > 0 ? newTop : 0
					this.$emit('on-resize', pos)
				}
				let up = () => {
					this.$emit('on-resize')
					document.onmousemove = function() {}
					document.onmouseup = function() {}
				}
				document.onmousemove = move
				document.onmouseup = up
			},
			findPosition() {

				let oElement = this.wrapId ? document.getElementById(this.wrapId) : document.body
				let x2 = 0;
				let y2 = 0;
				let width = oElement.clientWidth
				let height = oElement.clientHeight
				if(typeof(oElement.offsetParent) != 'undefined') {
					for(var posX = 0, posY = 0; oElement; oElement = oElement.offsetParent) {
						posX += oElement.offsetLeft;
						posY += oElement.offsetTop;
					}
					x2 = posX + width;
					y2 = posY + height;
					return [posX, posY, x2, y2, width, height];

				} else {
					x2 = oElement.x + width;
					y2 = oElement.y + height;
					return [oElement.x, oElement.y, x2, y2, width, height];
				}
			}
		}
	}
</script>

<style lang="scss" scoped>
	@import '../assets/scss/variables';
	.edit-shape-point {
		width: 15px;
		height: 15px;
		background-color: $white;
		border: 1px solid #59c7f9;
		border-radius: 10px;
		position: absolute;
		z-index: 1001;
	}
	
	.components-edit-shape {
		position: absolute;
		cursor: move;
		&.active {
			outline: 1px solid $primary;
		}
		&:hover {
			outline: 1px solid $primary;
		}
		&.locked {
			cursor: not-allowed;
			outline: 1px solid #ed4014;
			.edit-shape-point {
				border: 1px solid #ed4014;
			}
		}
	}
</style>